package server;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class MATM_Server {

	/**
	 * Class runs the server that the clients on different computers are able to
	 * communicate with through the sockets
	 * 
	 * @author XA9
	 */

	private boolean running = false;
	private final int port;
	private ServerSocket socket = null;
	private BankDatabase bankDB = null;
	byte key = 7;

	public MATM_Server(int port) {
		this.port = port;
		this.bankDB = new BankDatabase();
	}

	/**
	 * Creates a ServerSocket that waits for data from a client
	 */

	public void run() {

		this.running = true;

		try {

			String input;

			socket = new ServerSocket(this.port);
			System.out.println("Server is running...");
			while (this.running) {
				Socket connectionSocket = socket.accept();
				BufferedReader inFromClient = new BufferedReader(
						new InputStreamReader(connectionSocket.getInputStream()));

				DataOutputStream outToClient = new DataOutputStream(
						connectionSocket.getOutputStream());

				input = inFromClient.readLine();

				/**
				 * Writes the String input to a byte newInput
				 */

				byte[] newInput = input.getBytes();

				/**
				 * Runs the newInput byte through a for loop, Xor encrypting it
				 * with the given key
				 */

				for (int i = 0; i < newInput.length; i++) {
					newInput[i] = (byte) (newInput[i] ^ key);
				}

				String resp = this.tokens(input);

				/**
				 * Outprints the input and resp to the server screen
				 */

				System.out.println(input);

				System.out.println(resp);

				System.out.println("Received: " + input);

				/**
				 * Writes the resp input to a byte newResp
				 */

				byte[] newResp = resp.getBytes();

				/**
				 * Runs the newResp byte through a for loop, Xor encrypting it
				 * with the given key
				 */

				for (int i = 0; i < newResp.length; i++) {
					newResp[i] = (byte) (newResp[i] ^ key);
				}
				outToClient.writeBytes(resp + "\n");
			}

			/**
			 * Catches the program if there is an exception so the does not
			 * crashes if the connection is a little unstable
			 */

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

	}

	/**
	 * A stop function so that it is possible to stop the server and close the
	 * sockets with the application still running
	 * 
	 * @throws IOException
	 */

	public void stop() throws IOException {
		this.running = false;
		this.socket.close();
	}

	public String tokens(String msg) {

		String[] params = msg.split(":");
		String resp = "";

		/**
		 * Switch statement that gives the database input from the client to
		 * update in the SQL database
		 * 
		 * @return resp
		 */

		switch (params[0].toUpperCase().trim()) {

		case "AUTH":
			boolean rsp = this.bankDB.authenticateUser(params[1].trim(),
					params[2].trim());
			resp = Boolean.toString(rsp);
			break;
		case "BALANCE":
			double rsp1 = this.bankDB.getBalance(params[1].trim());
			resp = Double.toString(rsp1);
			break;
		case "BALANCEDKK":
			double rspx = this.bankDB.getBalance(params[1].trim());
			double rspbtc = rspx * (this.bankDB.btcRate());
			resp = Double.toString(rspbtc);
			break;
		case "DEPOSITDKK":
			double money = Double.parseDouble(params[2].trim());
			double moneyBtc = money / bankDB.btcRate();
			this.bankDB.DepositBtc(params[1].trim(), moneyBtc);
			break;
		case "DEPOSITBTC":
			double amountBtc = Double.parseDouble(params[2].trim());
			this.bankDB.DepositBtc(params[1].trim(), amountBtc);
			break;
		case "SENDB":
			double amount = Double.parseDouble(params[2].trim());
			this.bankDB.SendBtc(params[1].trim(), amount);
			break;
		default:
			System.out.println(params[0] + " isn't a valid parameter");
			resp = "ERROR";
			break;
		}

		return resp;

	}
}